package com.lobov.run;

//import java.util.ArrayList;
//import java.util.List;

import mpi.MPI;

import com.lobov.containers.MultiPair;
import com.lobov.entities.ContainerOfSnips;
import com.lobov.entities.Matrix;
import com.lobov.entities.Snip;
import com.lobov.entities.Timer;
import com.lobov.utils.Compressor;
import com.lobov.utils.Cutter;
import com.lobov.utils.Generator;

public class RunMPI {
	
//	private static List<Long> unCompressedVals = new ArrayList<Long>();
//	private static List<Long> compressedVals = new ArrayList<Long>();

	public static void main(String[] args) throws Exception {
		
		int h = 12; //размер матриц
		int val = 12;
		int startVal = 0;
		int endValue = 120;
		
		
//		startVal = val;
		while (val <= endValue) {
		// генерируем матрицу 1
		Matrix matrix1 = Generator.generateUnCompressedHorisontalMatrix(val,
				val, 0.2);
		// генерируем матрицу 2
		Matrix matrix2 = Generator.generateUnCompressedHorisontalMatrix(val,
				val, 0.2);
		
		//МЕТОДЫ ДЛЯ ТЕСТИРОВАНИЯ!!!
		sc1(matrix1, matrix2, val, false, args);
		
		val+=h;
		}
		
		
		
		
	}
	

	// генерируем и перемножаем две матрицы
	private static void sc1(Matrix matrix1, Matrix matrix2, int val, boolean doZip, String[] args)
			throws Exception {
			try {
				MPI.Init(args);
				int rank = MPI.COMM_WORLD.Rank();
				int size = MPI.COMM_WORLD.Size();
				actionTest(matrix1, matrix2, val, rank, size, doZip);
			} finally {
				MPI.Finalize();
			}
	}
	
	private static void actionTest(Matrix matrix1, Matrix matrix2, int val, int rank, int size, boolean doZip) throws Exception {

		// определяем массив для хранения перемножаемых сущностей
		MultiPair[] mps = new MultiPair[4];

		// определяем массив для хранения лоскутов после перемножения
		Snip[] sps = new Snip[4];

		switch (rank) {
		case 0: {
			
			// режем матрицу 2 на лоскуты и кладем в контейнер
			ContainerOfSnips cont = Cutter.cutMatrixHorizontal(matrix2, 3);

			// определяем массив лоскутов на перемножениеы
			Snip[] snips = cont.getSnips();
			
			if(doZip){
				matrix1 = Compressor.compressMatrix(matrix1);
			}
			
			// заполняем массив перемножаемых сущностей
			for (int i = 0; i < 3; i++) {
				
				if(doZip){
					Snip s = Compressor.compressSnip(snips[i]);
					mps[i] = new MultiPair(matrix1, s);	
				} else {
					mps[i] = new MultiPair(matrix1, snips[i]);
				}

			}
			Timer timer = new Timer();
			timer.startTimer();
			// отправляем на ноды контейнеры перемножаемых сущностей
			// и ждем ответных лоскутов TODO продумать как удобней получать
			// лоскуты в один массив
			for (int i = 1; i < 3; i++) {
				MPI.COMM_WORLD.Send(mps, i, 2, MPI.OBJECT, i, 100);
				MPI.COMM_WORLD.Recv(sps, i, 2, MPI.OBJECT, i, 100);
			}

			// производим вычисления с первым лоскутом на 0 процессоре
			sps[0] = (Snip) mps[0].compute();

			ContainerOfSnips newCont = new ContainerOfSnips(3,
					sps[0].getXlength());
			for (int i = 0; i < 3; i++) {
				newCont.setSnipByIndex(sps[i], i);
			}
			System.out.println(val + " X " + val + " - " + timer.getTime()
					+ " мс. формат - " + (doZip?"cжатый":"разреженный"));
			
//			if(doZip){
//				compressedVals.add(timer.getTime());
//			} else {
//				unCompressedVals.add(timer.getTime());
//			}
		}
			break;
		case 1: {
			MPI.COMM_WORLD.Recv(mps, 1, 2, MPI.OBJECT, 0, 100);
			sps[1] = (Snip) (mps[1].compute());
			MPI.COMM_WORLD.Send(sps, 1, 2, MPI.OBJECT, 0, 100);
		}
			break;
		case 2: {
			MPI.COMM_WORLD.Recv(mps, 2, 2, MPI.OBJECT, 0, 100);
			sps[2] = (Snip) (mps[2].compute());
			MPI.COMM_WORLD.Send(sps, 2, 2, MPI.OBJECT, 0, 100);
		}
			break;
		case 3: {
			// DOESN'T WORK !!! :(
		}
			break;

		}
		
	}
	
	
}
